package formuParse;

import calculatorBase.CalculatorBase;

import java.util.ArrayList;

import formuParse.Token;

public class Formula
{
	private int character_index = 0;
	public String formula_string;
	int error = 0;
	ArrayList<Token> stack = new ArrayList<Token>();
	ArrayList<Token> backup = new ArrayList<Token>();
	ArrayList<Token> output = new ArrayList<Token>();
	ArrayList<Integer> start_depth = new ArrayList<Integer>();
	ArrayList<Integer> param_depth = new ArrayList<Integer>();

	int depth = 0;
	public String name;
	public String basis;
	Token last_token = new Token();
	boolean pass = false;
	public CalculatorBase main_base;
	Formula temp_form;

	public void parse_declaration(String dec)
	{
		
		int index;
		for (index = 0; index < dec.length(); index++)
		{
			if (dec.charAt(index) == '(')
			{
				name = dec.substring(0, index);
				break;
			}
		}
		basis = dec.substring(index + 1, dec.length() - 1);
		temp_form = new Formula(main_base);
		temp_form.name = name;
		temp_form.basis = basis;

	}

	public boolean parse(String form)
	{
		main_base.parse_error = 0;
		boolean is_function = false;
		boolean had_paren = false;
		String declare = "";
		int index = 0;
		char temp_char;
		name = "";
		int open = 0;
		int close = 0;
		for (index = 0; index < form.length(); index++)
		{
			temp_char = form.charAt(index);
			if (!is_valid_char(temp_char))
			{
				main_base.parse_error = 1;
				return false;
			}
			if (temp_char == '(')
			{
				had_paren = true;
				open++;
			}
			if (temp_char == ')')
			{
				close++;
			}
			if (temp_char == ':')
			{
				temp_char = form.charAt(++index);
				if (temp_char == '=' && had_paren)
				{
					is_function = true;
					formula_string = form.substring(index + 1);
					declare = form.substring(0, index - 1);
					parse_declaration(declare);
				}
			}
		}
		if (!is_function)
		{
			formula_string = form;
		}
		if (open != close)
		{
			main_base.parse_error = 5;
			return false;
		}
		character_index = 0;
		error = 0;
		stack.clear();
		output.clear();
		start_depth.clear();
		param_depth.clear();
		depth = 0;
		Token last_token = new Token();
		boolean pass = false;

		boolean res = false;
		boolean continue_parsing = true;
		Token temp_token = new Token();
		last_token.done = true;
		while (continue_parsing)
		{
			temp_token = get_token();
			if (temp_token.done) // if im done, stop
			{
				continue_parsing = false;
				res = true;

				int stack_index = stack.size() - 1;
				for (stack_index = stack.size() - 1; stack_index >= 0; stack_index--)
				{
					if (stack.get(stack_index).operator != 5 && stack.get(stack_index).operator != 6 && stack.get(stack_index).operator != 7)
					{
						if (start_depth.size() != 0)
						{
							int i;
							for (i = 0; i < start_depth.size(); i++)
							{
								if (start_depth.get(i) == depth)
								{
									Token temp_token_e = new Token();
									temp_token_e.type = 1;
									temp_token_e.number = -1;
									output.add(temp_token_e);
									temp_token_e = new Token();
									temp_token_e.type = 2;
									temp_token_e.operator = 3;
									output.add(temp_token_e);
									start_depth.remove(i);
								}
							}
						}
					}
					output.add(stack.get(stack_index));
					stack.remove(stack_index);
				}

				if (start_depth.size() != 0)
				{
					Token temp_token_e = new Token();
					temp_token_e.type = 1;
					temp_token_e.number = -1;
					output.add(temp_token_e);
					temp_token_e = new Token();
					temp_token_e.type = 2;
					temp_token_e.operator = 3;
					output.add(temp_token_e);
					start_depth.clear();
				}
				if (is_function)
				{
					int i;
					for (i = 0; i < output.size(); i++)
					{
						temp_form.output.add(output.get(i));
					}
					for (i = 0; i < main_base.formula_system.size(); i++)
					{
						if (main_base.formula_system.get(i).name.equals(temp_form.name))
						{
							main_base.formula_system.remove(i);
						}
					}
					main_base.formula_system.add(temp_form);
				}
				break;
			}
			if (temp_token.error != 0) // if there was an error, stop, but
										// report that the parse failed
			{
				continue_parsing = false;
				res = false;
				break;
			}

			// special cases for the - sign
			if (temp_token.operator == 2)
			{

				if (((last_token.type == 2 || last_token.done) && last_token.operator != 7) && last_token.operator != 5)
				{
					start_depth.add(depth);
				}
				else if (last_token.operator == 5)
				{
					Token temp = new Token();
					temp.type = 1;
					temp.number = -1;
					output.add(temp);
					temp = new Token();
					temp.type = 2;
					temp.operator = 3;
					stack.add(stack.size(), temp);
				}
				else
				{
					pass = true;
				}
			}

			// start of the actual shunting yard algorithm

			if (temp_token.type == 3)
			{
				if (last_token.type == 1 || last_token.type == 4)
				{
					Token temp = new Token();
					temp.type = 2;
					temp.operator = 3;
					stack.add(temp);
				}
				stack.add(temp_token);

			}
			if (temp_token.type == 6)
			{
				output.add(temp_token);
				output.add(stack.get(stack.size() - 1));
				stack.remove(stack.size() - 1);
			}
			if (temp_token.type == 5)
			{
				int i;

				while (param_depth.size() < depth + 1)
				{
					param_depth.add(0);
				}

				param_depth.set(depth, param_depth.get(depth) + 1);
				for (i = 0; i < stack.size(); i++)
				{
					if (stack.get(stack.size() - 1).operator == 6)
					{
						break;
					}
					else
					{
						output.add(stack.get(stack.size() - 1));
						stack.remove(stack.size() - 1);
					}
				}
			}
			if (temp_token.type == 1 || temp_token.type == 4) // if it is a
																// number or a
																// variable

			{
				if (last_token.operator == 7)
				{
					Token temp = new Token();
					temp.type = 2;
					temp.operator = 3;
					stack.add(temp);
				}
				if (temp_token.type == 4)
				{
					if (last_token.type == 1 || last_token.type == 4)
					{
						Token temp = new Token();
						temp.type = 2;
						temp.operator = 3;
						stack.add(temp);
					}
				}
				output.add(temp_token); // add it to the output
				if (stack.size() != 0)
				{
					if (stack.get(stack.size() - 1).type == 3)
					{
						output.add(stack.get(stack.size() - 1));
						output.get(stack.size() - 1).params = param_depth.get(depth + 1);
						stack.remove(stack.get(stack.size() - 1));
					}
				}
			}

			if ((temp_token.type == 2 && temp_token.operator != 6 && temp_token.operator != 7) && ((temp_token.operator != 2 && temp_token.operator != 9) || pass))
			{

				int stack_index = stack.size() - 1;

				for (stack_index = stack.size() - 1; stack_index >= 0; stack_index--)
				{
					if ((temp_token.prec() >= stack.get(stack_index).prec() && stack.get(stack_index).operator != 6 && !is_right_assoc(stack.get(stack_index))) || (is_right_assoc(stack.get(stack_index))) && stack.get(stack_index).prec() < temp_token.prec())
					{
						output.add(stack.get(stack_index));
						stack.remove(stack_index);
					}
					else
					{
						break;
					}

				}
				stack.add(temp_token);
				if (temp_token.operator != 5 && temp_token.operator != 6 && temp_token.operator != 7 && temp_token.operator != 9)
				{
					if (start_depth.size() != 0)
					{
						int i;
						for (i = 0; i < start_depth.size(); i++)
						{
							if (start_depth.get(i) == depth)
							{
								Token temp_token_e = new Token();
								temp_token_e.type = 1;
								temp_token_e.number = -1;
								output.add(temp_token_e);
								temp_token_e = new Token();
								temp_token_e.type = 2;
								temp_token_e.operator = 3;
								output.add(temp_token_e);
								start_depth.remove(i);
							}
						}
					}
				}

			}

			if (temp_token.operator == 9)
			{
				stack.add(0, temp_token);
				Token temp = new Token();
				temp.type = 2;
				temp.operator = 6;
				stack.add(temp);
				depth++;
				while (param_depth.size() < depth + 1)
				{
					param_depth.add(0);
				}
				formula_string = formula_string + ")";
			}

			if (temp_token.type == 2 && temp_token.operator == 6)
			{
				if (last_token.type == 1 || last_token.type == 4 || last_token.operator == 7)
				{
					Token temp = new Token();
					temp.type = 2;
					temp.operator = 3;
					stack.add(temp);
				}
				stack.add(temp_token);
				depth++;
				while (param_depth.size() < depth + 1)
				{
					param_depth.add(0);
				}
			}
			if (temp_token.type == 2 && temp_token.operator == 7)
			{
				int i;
				if (last_token.type == 2 && last_token.operator == 6)
				{
					param_depth.set(depth, param_depth.get(depth) - 1);
				}
				for (i = 0; i < start_depth.size(); i++)
				{
					if (start_depth.get(i) == depth)
					{
						Token temp = new Token();
						temp.type = 1;
						temp.number = -1;
						output.add(temp);
						temp = new Token();
						temp.type = 2;
						temp.operator = 3;
						output.add(temp);
						start_depth.remove(i);
					}
				}

				depth--;
				int stack_index = stack.size() - 1;
				for (stack_index = stack.size() - 1; stack_index >= 0; stack_index--)
				{
					if (stack.get(stack_index).operator != 6)
					{
						output.add(stack.get(stack_index));
						stack.remove(stack_index);

					}
					else
					{
						stack.remove(stack_index);
						break;
					}
				}
				if (stack.size() != 0)
				{
					if (stack.get(stack.size() - 1).type == 3)
					{
						output.add(stack.get(stack.size() - 1));
						output.get(output.size() - 1).params = param_depth.get(depth + 1);
						stack.remove(stack.size() - 1);
					}
				}
			} // 3 4 2 * 1 5 − 2 3 ^ ^ / +
			last_token = temp_token;
			;
		}

		return res;
	}

	public Formula(CalculatorBase base)
	{
		main_base = base;
	}

	public double eval(double in)
	{
		main_base.eval_error = 0;
		if (main_base.calc_error())
		{
			return 0;
		}
		if (output.size() == 0)
		{
			main_base.eval_error = 1;
			return 0;
		}
		main_base.eval_error = 0;
		int i;
		backup.clear();
		for (i = 0; i < output.size(); i++)
		{

			backup.add(output.get(i));
			if (output.get(i).variable != null)
			{
				if (output.get(i).variable != "")
				{

					if (output.get(i).variable.equals(basis))
					{
						output.get(i).number = in;
						output.get(i).type = 1;
					}
					else
					{
						output.get(i).number = main_base.get_variable(output.get(i).variable);
						output.get(i).type = 1;
					}
				}
			}
		}

		while (output.size() != 1 && main_base.eval_error == 0)
		{
			for (i = 0; i < output.size(); i++)
			{
				Token temp_token = new Token();
				temp_token.type=1;

				if (output.get(i).type == 1)
				{
					if (i == output.size() - 1 && output.size() != 1)
					{
						main_base.eval_error = 1;
					}
				}
				if (output.get(i).operator == 9)
				{

					if (output.get(i - 2).variable != null && output.get(i - 1).type == 1)
					{
						main_base.set_variable(String.valueOf(output.get(i - 2).variable), output.get(i - 1).number);
						return output.get(i - 1).number;
					}
					else
					{
						main_base.eval_error = 2;
						return 0;
					}
				}
				if (output.get(i).type == 2)
				{
					if (output.size() >= 3)
					{
						if (output.get(i - 1).type == 1 && output.get(i - 2).type == 1)
						{
							if (output.get(i).operator == 1)
							{
								temp_token.number = output.get(i - 2).number + output.get(i - 1).number;
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 2)
							{
								temp_token.number = output.get(i - 2).number - output.get(i - 1).number;
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 3)
							{
								temp_token.number = output.get(i - 2).number * output.get(i - 1).number;
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 4)
							{
								temp_token.number = output.get(i - 2).number / output.get(i - 1).number;
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 5)
							{
								temp_token.number = java.lang.Math.pow(output.get(i - 2).number, output.get(i - 1).number);
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 8)
							{
								temp_token.number = ((int) output.get(i - 2).number % (int) output.get(i - 1).number);
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 11)
							{

								if (String.format("%.12G", output.get(i - 1).number).equals(String.format("%.12G", output.get(i - 2).number)))
								{
									temp_token.number = 1.0;
								}
								else
								{
									temp_token.number = 0.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 12)
							{
								if (output.get(i - 2).number > output.get(i - 1).number)
								{
									temp_token.number = 1.0;
								}
								else
								{
									temp_token.number = 0.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 13)
							{
								if (output.get(i - 2).number < output.get(i - 1).number)
								{
									temp_token.number = 1.0;
								}
								else
								{
									temp_token.number = 0.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 16)
							{

								if (String.format("%.12G", output.get(i - 1).number).equals(String.format("%.12G", output.get(i - 2).number)))
								{
									temp_token.number = 0.0;
								}
								else
								{
									temp_token.number = 1.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 15)
							{
								if (output.get(i - 2).number >= output.get(i - 1).number)
								{
									temp_token.number = 1.0;
								}
								else
								{
									temp_token.number = 0.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
							if (output.get(i).operator == 14)
							{
								if (output.get(i - 2).number <= output.get(i - 1).number)
								{
									temp_token.number = 1.0;
								}
								else
								{
									temp_token.number = 0.0;
								}
								output.remove(i - 2);
								output.remove(i - 2);
								output.set(i - 2, temp_token);
								break;
							}
						}
						else
						{
							main_base.eval_error = 2;
							return 0;
						}
					}
					else
					{
						main_base.eval_error = 1;
						return 0;
					}
					if (output.get(i - 1).type == 1)
					{
						if (output.get(i).operator == 10)
						{
							temp_token.number = factorial((int) output.get(i - 1).number);
							output.remove(i);
							output.set(i - 1, temp_token);
							break;
						}
					}
					else
					{
						main_base.eval_error = 2;
						return 0;
					}

				}
				if (output.get(i).type == 3)
				{
					int index;
					boolean temp_bool = false;
					for (index = 0; index < main_base.formula_system.size(); index++)
					{
						if (main_base.formula_system.get(index).name.equals(output.get(i).function))
						{
							temp_token = output.get(i - 1);
							temp_token.number = main_base.formula_system.get(index).eval(temp_token.number);
							temp_token.function = output.get(i).function;
							output.set(i - 1, temp_token);
							output.remove(i);
							temp_bool = true;
							i--;
							break;
						}
					}
					if (!temp_bool)
					{
						if (output.get(i).function.equals("derive"))
						{ // its a
							// magic
							// function
							// so we
							// need
							// to
							// parse
							// the
							// csv
							if (output.get(i - 1).type != 6)
							{
								main_base.eval_error = 2;
								return 0;
							}

							String temp_magic = output.get(i - 1).magic;
							String func = "";
							String var = "";
							String dub = "";
							int save = 0;
							int index2;
							for (index2 = 0; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									save = index2 + 1;
									func = temp_magic.substring(0, index2);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{

									var = temp_magic.substring(save, index2);
									if (!is_valid_name(var))
									{
										main_base.eval_error = 3;
										return 0;
									}
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (index2 == temp_magic.length() - 1)
								{

									dub = temp_magic.substring(save);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							Formula to_derive = new Formula(main_base);
							to_derive.parse(func);
							to_derive.basis = var;
							Formula x = new Formula(main_base);
							x.parse(dub);
							x.basis = basis;
							output.get(i).type = 1;
							output.get(i).number = derive(to_derive, x.eval(in));
							output.remove(i - 1);
							i--;

							if (main_base.calc_error())
							{
								return 0;
							}
							break;

						}
						if (output.get(i).function.equals("integrate"))
						{ 
							if (output.get(i - 1).type != 6)
							{
								main_base.eval_error = 2;
								return 0;
							}
							String temp_magic = output.get(i - 1).magic;
							String func = "";
							String var = "";
							String dub1 = "";
							String dub2 = "";
							int save = 0;
							int index2;
							for (index2 = 0; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									save = index2 + 1;
									func = temp_magic.substring(0, index2);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									if (!is_valid_name(var))
									{
										main_base.eval_error = 3;
										return 0;
									}
									var = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{

								if (temp_magic.charAt(index2) == ',')
								{
									dub1 = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (index2 == temp_magic.length() - 1)
								{

									dub2 = temp_magic.substring(save);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							Formula to_derive = new Formula(main_base);
							to_derive.parse(func);
							to_derive.basis = var;

							Formula x1 = new Formula(main_base);
							x1.parse(dub1);
							x1.basis = basis;
							Formula x2 = new Formula(main_base);
							x2.parse(dub2);
							x2.basis = basis;
							output.get(i).type = 1;
							output.get(i).number = integrate(to_derive, x1.eval(in), x2.eval(in));
							output.remove(i - 1);
							i--;
							if (main_base.calc_error())
							{
								return 0;
							}
							break;

						}
						if (output.get(i).function.equals("sum"))
						{ // its a
							// magic
							// function
							// so we
							// need to
							// parse the
							// csv
							if (output.get(i - 1).type != 6)
							{
								main_base.eval_error = 2;
								return 0;
							}
							String temp_magic = output.get(i - 1).magic;
							String func = "";
							String var = "";
							String dub1 = "";
							String dub2 = "";
							int save = 0;
							int index2;
							for (index2 = 0; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									save = index2 + 1;
									func = temp_magic.substring(0, index2);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									if (!is_valid_name(var))
									{
										main_base.eval_error = 3;
										return 0;
									}
									var = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{

								if (temp_magic.charAt(index2) == ',')
								{
									dub1 = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (index2 == temp_magic.length() - 1)
								{

									dub2 = temp_magic.substring(save);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							Formula to_sum = new Formula(main_base);
							to_sum.parse(func);
							to_sum.basis = var;

							Formula x1 = new Formula(main_base);
							x1.parse(dub1);
							x1.basis = basis;
							Formula x2 = new Formula(main_base);
							x2.parse(dub2);
							x2.basis = basis;
							int sumer;
							double sum = 0;
							for (sumer = (int) x1.eval(in); sumer < x2.eval(in) + sign(x2.eval(in)); sumer++)
							{
								sum += to_sum.eval(sumer);
							}
							output.get(i).type = 1;
							output.get(i).number = sum;
							output.remove(i - 1);
							i--;
							if (main_base.calc_error())
							{
								return 0;
							}
							break;
						}
						if (output.get(i).function.equals("product"))
						{ // its a
							// magic
							// function
							// so we
							// need
							// to
							// parse
							// the
							// csv
							if (output.get(i - 1).type != 6)
							{
								main_base.eval_error = 2;
								return 0;
							}
							String temp_magic = output.get(i - 1).magic;
							String func = "";
							String var = "";
							String dub1 = "";
							String dub2 = "";
							int save = 0;
							int index2;
							for (index2 = 0; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									save = index2 + 1;
									func = temp_magic.substring(0, index2);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (temp_magic.charAt(index2) == ',')
								{
									if (!is_valid_name(var))
									{
										main_base.eval_error = 3;
										return 0;
									}
									var = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{

								if (temp_magic.charAt(index2) == ',')
								{
									dub1 = temp_magic.substring(save, index2);
									save = index2 + 1;
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							for (index2 = save; index2 < temp_magic.length(); index2++)
							{
								if (index2 == temp_magic.length() - 1)
								{

									dub2 = temp_magic.substring(save);
									break;
								}
								if (index2 == temp_magic.length() - 1)
								{
									main_base.eval_error = 4;
									return 0;
								}
							}
							Formula to_prod = new Formula(main_base);
							to_prod.parse(func);
							to_prod.basis = var;

							Formula x1 = new Formula(main_base);
							x1.parse(dub1);
							x1.basis = basis;
							Formula x2 = new Formula(main_base);
							x2.parse(dub2);
							x2.basis = basis;
							int proder;
							double prod = 0;
							for (proder = (int) x1.eval(in); proder < x2.eval(in) + sign(x2.eval(in)); proder++)
							{
								prod *= to_prod.eval(proder);
							}
							output.get(i).type = 1;
							output.get(i).number = prod;
							output.remove(i - 1);
							i--;
							if (main_base.calc_error())
							{
								return 0;
							}
							break;
						}

						if (output.get(i).function.equals("log"))
						{
							if(output.get(i).params==1)
							{
							    temp_token.number = Math.log(output.get(i - 1).number) / Math.log(output.get(i - 2).number);
							}
							else
							{
								temp_token.number = Math.log(output.get(i - 1).number);
							}
							
							if(output.get(i).params==1)
							{
								output.set(i - 2, temp_token);
							    output.remove(i - 1);
							    output.remove(i-1);
							}
							else
							{
								output.set(i - 1, temp_token);
								output.remove(i);
						}
							
							break;
						}
						if (output.get(i).params == 1)
						{
							if (output.get(i - 1).type == 1 && output.get(i - 2).type == 1)
							{
								if (output.get(i).function.equals("npr"))
								{

									temp_token.number = npr(output.get(i - 2).number, output.get(i - 1).number);
									output.set(i - 2, temp_token);
									output.remove(i - 1);
									output.remove(i - 1);
									break;
								}
								if (output.get(i).function.equals("ncr"))
								{

									temp_token.number = ncr(output.get(i - 2).number, output.get(i - 1).number);
									output.set(i - 2, temp_token);
									output.remove(i - 1);
									output.remove(i - 1);
									break;
								}
							}
							else
							{
								main_base.eval_error = 2;
								return 0;
							}
						}
						else if (function_params(output.get(i).function) == 1)
						{
							main_base.eval_error = 4;
							return 0;
						}
						if (output.get(i).params == -1)
						{
							if (output.get(i).function.equals("clearAll"))
							{
								main_base.formula_system.clear();
								main_base.variable_rep.clear();
								main_base.variable_value.clear();
								temp_token.number = 1;
								output.set(i, temp_token);
								break;
							}
							if (output.get(i).function.equals("rnd"))
							{

								temp_token.number = main_base.rand_gen.nextDouble();
								output.set(i, temp_token);
								break;
							}
							if (output.get(i).function.equals("rndi"))
							{

								temp_token.number = main_base.rand_gen.nextInt(Integer.MAX_VALUE);
								output.set(i, temp_token);
								break;
							}
							if (output.get(i).function.equals("rndn"))
							{

								temp_token.number = main_base.rand_gen.nextGaussian();
								output.set(i, temp_token);
								break;
							}
							if (output.get(i).function.equals("rndb"))
							{

								boolean t = main_base.rand_gen.nextBoolean();
								if (t)
								{
									temp_token.number = 1;
								}
								else
								{
									temp_token.number = 0;
								}
								output.set(i, temp_token);
								break;
							}
						}
						else if (function_params(output.get(i).function) == -1)
						{
							main_base.eval_error = 4;
							return 0;
						}
						if (output.get(i).params == 0)
						{
							if (output.get(i).function.equals("delete"))
							{
								if (output.get(i - 1).variable == null)
								{
									if (output.get(i - 1).equals(""))
									{
										main_base.parse_error = 2;
										return 0;
									}
								}
								String magic = output.get(i - 1).magic;
								if (magic.charAt(magic.length() - 1) == ')')
								{
									String n = "";
									int search;
									for (search = 0; search < magic.length(); search++)
									{
										if (magic.charAt(search) == '(')
										{
											break;
										}
										n += magic.charAt(search);
									}
									for (search = 0; search < main_base.formula_system.size(); search++)
									{
										if (main_base.formula_system.get(search).name.equals(n))
										{
											main_base.formula_system.remove(search);
										}
									}
								}
								else
								{
									int search;
									for (search = 0; search < main_base.variable_rep.size(); search++)
									{
										if (main_base.variable_rep.get(search).equals(magic))
										{
											main_base.variable_rep.remove(search);
											main_base.variable_value.remove(search);
										}
									}
								}
								temp_token.number = 1;
								output.set(i - 1, temp_token);
								output.remove(i);
								break;
							}
							if (output.get(i - 1).type == 1)
							{
								if (output.get(i).function.equals("ln"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.log(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("sign"))
								{
									temp_token.number = sign(output.get(i - 1).number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("round"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.round(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("ipart"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = ipart(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}

								if (output.get(i).function.equals("fpart"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = fpart(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("isPrime"))
								{
									temp_token = output.get(i - 1);
									if (is_prime(temp_token.number))
									{
										temp_token.number = 1.0;
									}
									else
									{
										temp_token.number = 0;
									}
									main_base.rand_gen.setSeed((long) temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("seed"))
								{
									temp_token = output.get(i - 1);
									main_base.rand_gen.setSeed((long) temp_token.number);
									temp_token.number = 1;
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("floor"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = floor(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("int"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = floor(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("ciel"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = ciel(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("abs"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.abs(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("cos"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.cos(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("sin"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.sin(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("tan"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.tan(temp_token.number);
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("sec"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = 1 / Math.cos(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("csc"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = 1 / Math.sin(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("cot"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = 1 / Math.tan(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("acos"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.acos(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("asin"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.asin(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("atan"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.atan(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("asec"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.acos(1 / temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("acsc"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.asin(1 / temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("acot"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = from_radian(Math.atan(1 / temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("cosh"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.cosh(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("sinh"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.sinh(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
								if (output.get(i).function.equals("tanh"))
								{
									temp_token = output.get(i - 1);
									temp_token.number = Math.tanh(to_radian(temp_token.number));
									output.set(i - 1, temp_token);
									output.remove(i);
									break;
								}
							}
							else
							{
								main_base.eval_error = 2;
								return 0;
							}
						}
						else if (function_params(output.get(i).function) == 0)
						{
							main_base.eval_error = 4;
							return 0;
						}

					}
				}
			}
		}
		double out = output.get(0).number;
		output.clear();
		for (i = 0; i < backup.size(); i++)
		{
			output.add(backup.get(i));
		}
		backup.clear();
		return out;
	}

	public String st()
	{
		String temp = "";
		int i;
		for (i = 0; i < output.size(); i++)
		{
			temp += " " + token_to_string(output.get(i));
		}
		return temp;
	}

	public int error_code()
	{
		return error;
	}

	public String error_string()
	{
		if (error == 1)
		{
			return "Imbalance of ( )s";
		}
		else
		{
			return "No Error";
		}
	}

	public Token get_token()
	{
		Token temp_token = new Token(); // declare the temporary token
		char temp_char;

		if (character_index >= formula_string.length())
		{
			temp_token.done = true;
			return temp_token;
		}

		temp_char = formula_string.charAt(character_index);// grab the character

		while (Character.isWhitespace(temp_char)) // keep
													// grabbing
													// till
													// you
													// are
													// out
													// of
													// whitespace
		{
			character_index++;
			temp_char = formula_string.charAt(character_index);
		}
		if (stack.size() > 0)
		{
			if (stack.get(stack.size() - 1).type == 3 && is_magic_function(stack.get(stack.size() - 1).function))
			{
				int temp_depth = 0;
				if (temp_char == '(')
				{
					character_index++;
					temp_depth++;
					int i;
					for (i = character_index; i < formula_string.length(); i++)
					{
						if (formula_string.charAt(i) == '(')
						{
							temp_depth++;
						}
						if (formula_string.charAt(i) == ')')
						{
							temp_depth--;
							if (temp_depth == 0)
							{
								temp_token.magic = formula_string.substring(character_index, i);
								temp_token.type = 6;
								character_index = i + 1;
								return temp_token;
							}
						}
					}
				}
			}
		}
		if (temp_char == ':')
		{
			character_index++;
			temp_char = formula_string.charAt(character_index);
			if (temp_char == '=')
			{
				temp_token.type = 2;
				temp_token.operator = 9;
				character_index++;
				return temp_token;
			}
		}
		if (is_number(temp_char)) // if it is a number
		{
			String the_E_number = "";
			String the_whole_number = "";
			while (is_number(temp_char))
			{
				the_whole_number = the_whole_number + String.valueOf(temp_char);
				if ((character_index + 1 >= formula_string.length()) == false)
				{
					character_index++;
					temp_char = formula_string.charAt(character_index);
				}
				else
				{

					temp_char = ' ';
					character_index++;
					break;
				}
			}

			if (temp_char == 'E')
			{
				character_index++;

				temp_char = formula_string.charAt(character_index);
				while (temp_char == '0' || temp_char == '1' || temp_char == '2' || temp_char == '3' || temp_char == '4' || temp_char == '5' || temp_char == '6' || temp_char == '7' || temp_char == '8' || temp_char == '9' || temp_char == '−' || temp_char == '-' || temp_char == '+')
				{
					if (temp_char == '+')
					{
						character_index++;
						temp_char = formula_string.charAt(character_index);
						continue;
					}
					the_E_number += temp_char;
					character_index++;
					if (character_index >= formula_string.length())
					{
						break;
					}
					temp_char = formula_string.charAt(character_index);

				}
			}
			temp_char = ' ';
			temp_token.type = 1;
			if (the_E_number == "")
			{
				temp_token.number = Double.valueOf(the_whole_number);
			}
			else
			{
				temp_token.number = Double.valueOf(the_whole_number) * Math.pow(10, Double.valueOf(the_E_number));
			}
		}

		// if it is supported operator set up the token
		else if (temp_char == '+')
		{
			temp_token.type = 2;
			temp_token.operator = 1;
			character_index++;
		}
		else if ((temp_char == '−' || temp_char == '-') && !(is_number(formula_string.charAt(character_index))))
		{
			temp_token.type = 2;
			temp_token.operator = 2;
			character_index++;
		}
		else if ((temp_char == '−' || temp_char == '-') && (is_number(formula_string.charAt(character_index))))
		{
			String the_whole_number = "";
			while (is_number(temp_char))
			{
				the_whole_number = the_whole_number + String.valueOf(temp_char);
				if ((character_index + 1 >= formula_string.length()) == false)
				{
					character_index++;
					temp_char = formula_string.charAt(character_index);
				}
				else
				{
					character_index++;
					temp_char = ' ';
					break;
				}
			}
			temp_token.type = 1;
			temp_token.number = Double.valueOf(the_whole_number);

		}
		else if (temp_char == '*')
		{
			temp_token.type = 2;
			temp_token.operator = 3;
			character_index++;
		}
		else if (temp_char == '/')
		{
			temp_token.type = 2;
			temp_token.operator = 4;
			character_index++;
		}
		else if (temp_char == '^')
		{
			temp_token.type = 2;
			temp_token.operator = 5;
			character_index++;
		}
		else if (temp_char == '(')
		{
			temp_token.type = 2;
			temp_token.operator = 6;
			character_index++;
		}
		else if (temp_char == ')')
		{
			temp_token.type = 2;
			temp_token.operator = 7;
			character_index++;
		}
		else if (temp_char == '%')
		{
			temp_token.type = 2;
			temp_token.operator = 8;
			character_index++;
		}
		else if (temp_char == '!')
		{
			temp_token.type = 2;
			temp_token.operator = 10;
			character_index++;
		}
		else if (temp_char == '=')
		{
			temp_token.type = 2;
			temp_token.operator = 11;
			character_index++;
		}
		else if (temp_char == '>')
		{
			temp_token.type = 2;
			temp_token.operator = 12;
			character_index++;
		}
		else if (temp_char == '<')
		{
			temp_token.type = 2;
			temp_token.operator = 13;
			character_index++;
		}
		else if (temp_char == '≤')
		{
			temp_token.type = 2;
			temp_token.operator = 14;
			character_index++;
		}
		else if (temp_char == '≥')
		{
			temp_token.type = 2;
			temp_token.operator = 15;
			character_index++;
		}
		else if (temp_char == '≠')
		{
			temp_token.type = 2;
			temp_token.operator = 16;
			character_index++;
		}
		// end of opperator checks

		else if (is_letter(temp_char)) // if it is a variable or function
		{

			String var = "";
			while (is_letter(temp_char))
			{
				var = var + String.valueOf(temp_char);
				if ((character_index + 1 >= formula_string.length()) == false)
				{
					character_index++;
					temp_char = formula_string.charAt(character_index);
				}
				else
				{
					character_index++;
					temp_char = ' ';
					break;
				}
			}
			if (is_function(String.valueOf(var))) // we were wrong its
													// actually a
													// function
			{
				temp_token = get_function_token(var); // get the token that
														// represents that
														// function
			}
			else
			// yay we were right it is a variable
			{
				temp_token.type = 4;
				temp_token.variable = var;
			}

		}

		if (temp_char == ',')
		{
			temp_token.type = 5;
			character_index++;
		}

		if (!(character_index < formula_string.length()))
		{
			temp_token.function = "EOS";
		}

		if (character_index == -1) // nothing happened, an unknown error
		{
			temp_token.error = -1; // inform the parser there is an unknown
									// error, the parser will stop
		}
		return temp_token;
	}

	private boolean is_number(char test)
	{
		String digits = "0123456789.";
		boolean ret = false;
		int i;
		for (i = 0; i < 11; i++)
		{
			if (test == digits.charAt(i))
			{
				ret = true;
			}
		}
		return ret;
	}

	private boolean is_right_assoc(Token tok)
	{
		if (tok.operator == 5 || tok.operator == 9 || tok.operator == 10)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	private boolean is_letter(char test)
	{
		String letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψω";
		boolean ret = false;
		int i;
		for (i = 0; i < letters.length(); i++)
		{
			if (test == letters.charAt(i))
			{
				ret = true;
			}
		}
		return ret;
	}

	private int function_params(String test)
	{
		int i;
		for (i = 0; i < main_base.formula_system.size(); i++)
		{
			if (main_base.formula_system.get(i).name.equals(test))
			{
				return 1;
			}
		}
		if (test.equals("sum"))
		{
			return 3;
		}
		if (test.equals("product"))
		{
			return 3;
		}
		if (test.equals("clearAll"))
		{
			return -1;
		}
		if (test.equals("delete"))
		{
			return 0;
		}
		if (test.equals("isPrime"))
		{
			return 0;
		}
		if (test.equals("abs"))
		{
			return 0;
		}
		if (test.equals("derive"))
		{
			return 2;
		}
		if (test.equals("integrate"))
		{
			return 3;
		}
		if (test.equals("seed"))
		{
			return 0;
		}
		if (test.equals("rnd"))
		{
			return -1;
		}
		if (test.equals("rndn"))
		{
			return -1;
		}
		if (test.equals("rndi"))
		{
			return -1;
		}
		if (test.equals("rndb"))
		{
			return -1;
		}
		if (test.equals("ln"))
		{
			return 0;
		}
		if (test.equals("npr"))
		{
			return 1;
		}
		if (test.equals("ncr"))
		{
			return 1;
		}
		if (test.equals("log"))
		{
			return 0;
		}
		if (test.equals("round"))
		{
			return 0;
		}
		if (test.equals("ipart"))
		{
			return 0;
		}
		if (test.equals("fpart"))
		{
			return 0;
		}
		if (test.equals("int"))
		{
			return 0;
		}
		if (test.equals("floor"))
		{
			return 0;
		}
		if (test.equals("ciel"))
		{
			return 0;
		}
		if (test.equals("sign"))
		{
			return 0;
		}
		if (test.equals("cos"))
		{
			return 0;
		}
		else if (test.equals("sin"))
		{
			return 0;
		}
		else if (test.equals("tan"))
		{
			return 0;
		}
		else if (test.equals("acos"))
		{
			return 0;
		}
		else if (test.equals("asin"))
		{
			return 0;
		}
		else if (test.equals("atan"))
		{
			return 0;
		}
		else if (test.equals("csc"))
		{
			return 0;
		}
		else if (test.equals("sec"))
		{
			return 0;
		}
		else if (test.equals("cot"))
		{
			return 0;
		}
		else if (test.equals("acsc"))
		{
			return 0;
		}
		else if (test.equals("asec"))
		{
			return 0;
		}
		else if (test.equals("acot"))
		{
			return 0;
		}
		else if (test.equals("cosh"))
		{
			return 0;
		}
		else if (test.equals("sinh"))
		{
			return 0;
		}
		else if (test.equals("tanh"))
		{
			return 0;
		}
		else
		{
			return 0;
		}
	}

	private boolean is_function(String test)
	{
		int i;
		for (i = 0; i < main_base.formula_system.size(); i++)
		{
			if (main_base.formula_system.get(i).name.equals(test))
			{
				return true;
			}
		}
		if (test.equals("sum"))
		{
			return true;
		}
		if (test.equals("product"))
		{
			return true;
		}
		if (test.equals("clearAll"))
		{
			return true;
		}
		if (test.equals("delete"))
		{
			return true;
		}
		if (test.equals("isPrime"))
		{
			return true;
		}
		if (test.equals("abs"))
		{
			return true;
		}
		if (test.equals("derive"))
		{
			return true;
		}
		if (test.equals("integrate"))
		{
			return true;
		}
		if (test.equals("seed"))
		{
			return true;
		}
		if (test.equals("rnd"))
		{
			return true;
		}
		if (test.equals("rndn"))
		{
			return true;
		}
		if (test.equals("rndi"))
		{
			return true;
		}
		if (test.equals("rndb"))
		{
			return true;
		}
		if (test.equals("ln"))
		{
			return true;
		}
		if (test.equals("npr"))
		{
			return true;
		}
		if (test.equals("ncr"))
		{
			return true;
		}
		if (test.equals("log"))
		{
			return true;
		}
		if (test.equals("round"))
		{
			return true;
		}
		if (test.equals("ipart"))
		{
			return true;
		}
		if (test.equals("fpart"))
		{
			return true;
		}
		if (test.equals("int"))
		{
			return true;
		}
		if (test.equals("floor"))
		{
			return true;
		}
		if (test.equals("ciel"))
		{
			return true;
		}
		if (test.equals("sign"))
		{
			return true;
		}
		if (test.equals("cos"))
		{
			return true;
		}
		else if (test.equals("sin"))
		{
			return true;
		}
		else if (test.equals("tan"))
		{
			return true;
		}
		else if (test.equals("acos"))
		{
			return true;
		}
		else if (test.equals("asin"))
		{
			return true;
		}
		else if (test.equals("atan"))
		{
			return true;
		}
		else if (test.equals("csc"))
		{
			return true;
		}
		else if (test.equals("sec"))
		{
			return true;
		}
		else if (test.equals("cot"))
		{
			return true;
		}
		else if (test.equals("acsc"))
		{
			return true;
		}
		else if (test.equals("asec"))
		{
			return true;
		}
		else if (test.equals("acot"))
		{
			return true;
		}
		else if (test.equals("cosh"))
		{
			return true;
		}
		else if (test.equals("sinh"))
		{
			return true;
		}
		else if (test.equals("tanh"))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	private Token get_function_token(String test)
	{
		Token temp = new Token();
		temp.type = 3;
		temp.function = test;
		return temp;
	}

	public String token_to_string(Token in)
	{
		if (in.done)
		{
			return "EOS";
		}
		if (in.error != 0)
		{
			return "error number:" + String.valueOf(in.error);
		}
		if (in.type == 1)
		{
			return String.valueOf(in.number);
		}
		if (in.type == 2)
		{
			if (in.operator == 1)
			{
				return "+";
			}
			if (in.operator == 2)
			{
				return "-";
			}
			if (in.operator == 3)
			{
				return "*";
			}
			if (in.operator == 4)
			{
				return "/";
			}
			if (in.operator == 5)
			{
				return "^";
			}
			if (in.operator == 6)
			{
				return "(";
			}
			if (in.operator == 7)
			{
				return ")";
			}
			if (in.operator == 8)
			{
				return "%";
			}
			if (in.operator == 9)
			{
				return ":=";
			}
		}
		if (in.type == 3)
		{
			return in.function;
		}
		if (in.type == 4)
		{
			return in.variable;
		}
		else
		{
			return "error";
		}

	}

	boolean is_magic_function(String in)
	{
		if (in.equals("derive") || in.equals("integrate") || in.equals("delete") || in.equals("sum") || in.equals("product"))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	boolean is_valid_char(char in)
	{
		String check = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+=-_ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψω, ./*^%!:()1234567890<>≤≥≠";
		int i;
		for (i = 0; i < check.length(); i++)
		{
			if (check.charAt(i) == in)
			{
				return true;
			}
		}
		return false;
	}

	boolean is_valid_name(String in)
	{
		int i;
		for (i = 0; i < in.length(); i++)
		{
			if (!is_letter(in.charAt(i)))
			{
				return false;
			}
		}
		return true;
	}

	public static double derive(Formula f, double x)
	{
		double h = Math.pow(1E-1, 1.0 / 3.0) * x;
		double err = 0;
		int i, j;
		double errt, fac, hh, ans = 0;
		double a[][] = new double[10][10];

		hh = h;
		a[1][1] = (f.eval(x + hh) - f.eval(x - hh)) / (2.0 * hh);
		err = 1E30;
		for (i = 2; i < 10; i++)
		{
			hh /= 1.4;
			a[1][i] = (f.eval(x + hh) - f.eval(x - hh)) / (2.0 * hh);
			fac = 1.4 * 1.4;
			for (j = 2; j < i; j++)
			{
				a[j][i] = (a[j - 1][i] * fac - a[j - 1][i - 1]) / (fac - 1.0);
				fac = 1.4 * 1.4 * fac;
				errt = Math.max(Math.abs(a[j][i] - a[j - 1][i]), Math.abs(a[j][i] - a[j - 1][i - 1]));

				if (errt <= err)
				{
					err = errt;
					ans = a[j][i];
				}
			}
			if (Math.abs(a[i][i] - a[i - 1][i - 1]) >= 2.0 * (err))
			{
				break;
			}
		}
		return ans;
	}

	static public double adaptiveSimpsonsAux(Formula f, double a, double b, double epsilon, double S, double fa, double fb, double fc, int bottom)
	{
		double c = (a + b) / 2;
		double h = b - a;
		double d = (a + c) / 2;
		double e = (c + b) / 2;
		double fd = f.eval(d);
		double fe = f.eval(e);
		double Sleft = (h / 12) * (fa + 4 * fd + fc);
		double Sright = (h / 12) * (fc + 4 * fe + fb);
		double S2 = Sleft + Sright;
		if (bottom <= 0 || Math.abs(S2 - S) <= 15 * epsilon)
		{
			return S2 + (S2 - S) / 15;
		}
		else
		{
			return adaptiveSimpsonsAux(f, a, c, epsilon / 2, Sleft, fa, fc, fd, bottom - 1) + adaptiveSimpsonsAux(f, c, b, epsilon / 2, Sright, fc, fb, fe, bottom - 1);
		}
	}

	static public double integrate(Formula f, double start, double stop)
	{

		double c = (start + stop) / 2;
		double h = stop - start;
		double fa = f.eval(start);
		double fb = f.eval(stop);
		double fc = f.eval(c);
		double S = (h / 6) * (fa + 4 * fc + fb);
		return adaptiveSimpsonsAux(f, start, stop, 1E-15, S, fa, fb, fc, 10);
	}

	double sign(double in)
	{
		if (in > 0)
		{
			return 1.0;
		}
		else if (in < 0)
		{
			return -1;
		}
		else
		{
			return 0;
		}
	}

	double floor(double in)
	{
		double r = Math.abs(Math.round(in));
		if (r > Math.abs(in)) // rounded up
		{
			if (sign(in) == 1)
			{
				return sign(in) * (r - 1);
			}
			else
			{
				return sign(in) * r;
			}
		}
		else if (r < Math.abs(in)) // rounded down
		{
			if (sign(in) == 1)
			{
				return sign(in) * r;
			}
			else
			{
				return sign(in) * (r + 1);
			}
		}
		else
		// it was allready an integer
		{
			return in;
		}
	}

	double ciel(double in)
	{
		double r = Math.abs(Math.round(in));
		if (r > Math.abs(in)) // rounded up
		{
			if (sign(in) == 1)
			{
				return sign(in) * (r);
			}
			else
			{
				return sign(in) * (r - 1);
			}
		}
		else if (r < Math.abs(in)) // rounded down
		{
			if (sign(in) == 1)
			{
				return sign(in) * (r + 1);
			}
			else
			{
				return sign(in) * r;
			}
		}
		else
		// it was allready an integer
		{
			return in;
		}
	}

	double ipart(double in)
	{
		return (double) (int) in;
	}

	double fpart(double in)
	{
		double r = Math.abs(ipart(in));
		return sign(in) * (Math.abs(in) - r);
	}

	double factorial(int in)
	{
		int r = Math.abs(in);
		if (r == 0)
		{
			return 1;
		}
		else if (r == 1)
		{
			return 1;
		}
		else
		{
			int i;
			double m = 1;
			for (i = 2; i < r + 1; i++)
			{
				m *= i;
			}
			return m * sign(in);
		}

	}

	double ncr(double n, double r)
	{
		return (factorial((int) n) / (factorial((int) (n - r)) * factorial((int) r)));
	}

	double npr(double n, double r)
	{
		return (factorial((int) n) / (factorial((int) (n - r))));
	}

	boolean is_prime(double in)
	{
		long r = (long) Math.abs(in);
		int i;
		for (i = 2; i < r - 1; i++)
		{
			if (r % i == 0 && r != 2)
			{
				return false;
			}
		}
		return true;
	}

	double to_radian(double in)
	{
		int a = main_base.set.get_angle_unit();
		if (a == 0)
		{
			return ((in / 360) * (2 * Math.PI));
		}
		else if (a == 1)
		{
			return in;
		}
		else if (a == 2)
		{
			return (in / 100) * (2 * Math.PI);
		}
		else if (a == 3)
		{
			return in * (2 * Math.PI);
		}
		else
		{
			return 0;
		}
	}

	double from_radian(double in)
	{
		int a = main_base.set.get_angle_unit();
		if (a == 0)
		{
			return ((in * 360) / (2 * Math.PI));
		}
		else if (a == 1)
		{
			return in;
		}
		else if (a == 2)
		{
			return (in * 100) / (2 * Math.PI);
		}
		else if (a == 3)
		{
			return in / (2 * Math.PI);
		}
		else
		{
			return 0;
		}
	}
}
